#include <stdio.h>
#include <gtk/gtk.h>
#include <string.h>
#include <cairo.h>
#include <stdlib.h>
#include <time.h>
#include <sqlite3.h>
// 游戏常量
#define MAX_SNAKE_LENGTH 200
#define GRID_WIDTH 20
#define GRID_HEIGHT 20
//枚举上下左右方向
typedef enum { UP, DOWN, LEFT, RIGHT } Direction;

typedef struct {
    int x, y;
} Point;

typedef struct {
    Point body[MAX_SNAKE_LENGTH];
    int length;
    Direction dir;
} Snake;

void init_snake(Snake *snake, int startX, int startY) {
    snake->length = 3;
    snake->dir = RIGHT;
    for (int i = 0; i < snake->length; ++i) {
        snake->body[i].x = startX - i;//让蛇头的位置在最右边，从头到尾，从左往右定义蛇的身体
        snake->body[i].y = startY;//头尾的y值相等，即蛇初始位置水平
    }
}

void move_snake(Snake *snake, int grow) {
    // 如果吃到食物，grow=1，否则grow=0
    Point new_head = snake->body[0];
    switch (snake->dir) {//在屏幕坐标系中原点位置在左上角，下为y轴正向，右为x轴正向
        case UP:    new_head.y -= 1; break;
        case DOWN:  new_head.y += 1; break;
        case LEFT:  new_head.x -= 1; break;
        case RIGHT: new_head.x += 1; break;
    }//在这里找到了新的头的定义
    // 身体后移
    if (!grow) {
        //用memmove相当于把之前每一部位的坐标（其实是指针）赋给了他上一个身体部位，而length-1相当于没有位置去存放尾节点的位置使得尾节点位置丢失
        // 或者可以想象成把头去掉，每个节点都挪到了他前面那个节点的位置
        memmove(&snake->body[1], &snake->body[0], sizeof(Point) * (snake->length - 1));
        snake->body[0] = new_head;
        //把新的头再拼接到最前方，也就是说抛弃一个尾节点，新增一个头节点，长度不变，位置都加了1
    } else {
        //相同道理，这里没有-1是因为吃到食物了，长度+1
        memmove(&snake->body[1], &snake->body[0], sizeof(Point) * (snake->length));
        snake->body[0] = new_head;
        snake->length++;
    }
}

void change_direction(Snake *snake, Direction new_dir) {
    // 防止直接反向,如果新方向与旧方向相反就不做任何处理
    if ((snake->dir == UP && new_dir == DOWN) ||
        (snake->dir == DOWN && new_dir == UP) ||
        (snake->dir == LEFT && new_dir == RIGHT) ||
        (snake->dir == RIGHT && new_dir == LEFT)) {
        return;
    }
    snake->dir = new_dir;//不相反就改变方向
}

int check_self_collision(const Snake *snake) {
    for (int i = 1; i < snake->length; ++i) {
        if (snake->body[0].x == snake->body[i].x && snake->body[0].y == snake->body[i].y) {
            return 1;//只要头节点的(x,y)与任意身体节点的(x,y)相同，即判断为撞击身体，返回1
        }
    }
    return 0;
}

int check_wall_collision(const Snake *snake, int width, int height) {//判断是否撞墙
    if (snake->body[0].x < 0 || snake->body[0].x >= width ||
        snake->body[0].y < 0 || snake->body[0].y >= height) {//小于0是左方和上方边界的判定，width和height则是右边和下边
        return 1;
    }
    return 0;
}
//判断是否撞障碍物
int check_obstacle_collision(const Snake *snake, const Point *obstacles, int obstacle_count) {
    for (int i = 0; i < obstacle_count; ++i) {
        if (snake->body[0].x == obstacles[i].x && snake->body[0].y == obstacles[i].y) {//与判断和身体相撞的原理相同
            return 1;
        }
    }
    return 0;
}

int check_food_collision(const Snake *snake, const Point *food) {
    return (snake->body[0].x == food->x && snake->body[0].y == food->y);//撞到食物的坐标就返回1，否则返回0
}
// 难度枚举
typedef enum {
    EASY, // 菜鸟
    MEDIUM, // 一般
    HARD // 困难
} Difficulty;

// 全局变量
Snake snake;
Point food = {5, 5};
Point *obstacles = NULL;//obstacles:障碍物
int obstacle_count = 0;
int game_grid_width = 0;
int game_grid_height = 0;
int score = 0;
Difficulty current_difficulty;
sqlite3 *db;
char current_username[50] = ""; // 当前登录的用户名
int total_score = 0; // 累计总分
time_t start_time; // 游戏开始时间
gboolean is_recording = FALSE; // 是否记录分数
GtkWidget *global_rank_list = NULL; // 全局排行榜标签控件
gboolean is_paused = FALSE;//游戏是否暂停

// 函数声明
static GtkWidget* create_game_page(int gridCount, int speed_ms);
static void on_game_window_destroy(GtkWidget *widget, gpointer data);
static void free_obstacles();
static int init_database();
static int register_user(const char *username, const char *password);
static int login_user(const char *username, const char *password);
static GtkWidget* create_login_page(GtkStack *stack);
static GtkWidget* create_register_page(GtkStack *stack);
static int save_score(const char *username, int score, int time_used);
static void update_rank_list(GtkWidget *rank_list);

// 绘制回调函数                                          可以把这里 ↓ 的cr理解为是个画笔（上下文），画图操作基本都是操控这个画笔执行的
static gboolean draw_game_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
    int width = gtk_widget_get_allocated_width(widget);
    int height = gtk_widget_get_allocated_height(widget);//设置画布尺寸

    // 绘制网格
    cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);//设置颜色
    cairo_set_line_width(cr, 1);
    //画水平线
    for (int y = 0; y <= height; y += GRID_HEIGHT) {//循环，每次y坐标都会增加GRID_HEIGHT个像素，也就是说每条水平线之间的距离为GRID_HEIGHT
        cairo_move_to(cr, 0, y);//设置起点为0，即左边界
        cairo_line_to(cr, width, y);//设置终点，即右边界
        cairo_stroke(cr);//画线
    }
    //同上，画垂直线
    for (int x = 0; x <= width; x += GRID_WIDTH) {
        cairo_move_to(cr, x, 0);
        cairo_line_to(cr, x, height);
        cairo_stroke(cr);
    }

    // 绘制蛇
    cairo_set_source_rgb(cr, 0.1, 0.8, 0.1);
    cairo_set_line_width(cr, 0);//设置线粗为0，即无描边
    for (int i = 0; i < snake.length; ++i) {
        cairo_rectangle(cr,     // 绘制矩形（蛇身节点）
                        snake.body[i].x * GRID_WIDTH,   //矩形左上角x坐标
                        snake.body[i].y * GRID_HEIGHT,  //矩形左上角y坐标
                        GRID_WIDTH,        //矩形宽度
                        GRID_HEIGHT);     //矩形高度
        cairo_fill(cr);     //填充
    }

    // 绘制食物，逻辑和上面画蛇没区别，包括下面的障碍物，就不赘述了
    cairo_set_source_rgb(cr, 0.9, 0.2, 0.2);
    cairo_rectangle(cr,
                    food.x * GRID_WIDTH,
                    food.y * GRID_HEIGHT,
                    GRID_WIDTH,
                    GRID_HEIGHT);
    cairo_fill(cr);

    // 绘制障碍物
    cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
    for (int i = 0; i < obstacle_count; ++i) {
        cairo_rectangle(cr,
                        obstacles[i].x * GRID_WIDTH,
                        obstacles[i].y * GRID_HEIGHT,
                        GRID_WIDTH,
                        GRID_HEIGHT);
        cairo_fill(cr);
    }

    // 绘制分数
    cairo_set_source_rgb(cr, 0, 0, 0);
    char score_text[20];
    sprintf(score_text, "scores: %d", score);//格式化输出，把分数写到字符串里面
    //设置字体："Arial"是一种字体，CAIRO_FONT_SLANT_NORMAL表示正常字体（非斜体），CAIRO_FONT_WEIGHT_BOLD表示字体加粗
    cairo_select_font_face(cr, "Arial", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
    cairo_set_font_size(cr, 16);  // 字体大小（16像素）
    cairo_move_to(cr, 10, 20);   //字体位置（x,y）
    cairo_show_text(cr, score_text);//绘制文字

    // 绘制当前难度
    char diff_text[20];
    switch(current_difficulty) {
        case EASY: strcpy(diff_text, "rookie"); break;
        case MEDIUM: strcpy(diff_text, "common"); break;
        case HARD: strcpy(diff_text, "difficult"); break;
    }
    cairo_move_to(cr, width - 100, 20);  // 文字位置（右上角，x=宽度-100，y=20），cairo_move_to函数表示cr当前的位置
    cairo_show_text(cr, diff_text);       //依旧绘制文字

    // 添加暂停状态显示
    if (is_paused) {
        cairo_set_source_rgb(cr, 1, 0, 0); // 红色字体
        cairo_set_font_size(cr, 24);
        cairo_move_to(cr, width / 2 - 40, height / 2);
        cairo_show_text(cr, "PAUSED");
    }

    return FALSE;
}

// 保存分数到数据库
static int save_score(const char *username, int score, int time_used) {
    const char *sql = "INSERT INTO scores (username, score, time_used) VALUES (?, ?, ?);"; //数据库语句，表示插入，用?占位
    sqlite3_stmt *stmt;
    //sqlite3_prepare_v2用于将SQL文本编译为可执行的字节码对象（即 sqlite3_stmt）
    //db即数据库句柄，sql是要处理的语句，第三个参数是要编译的字节数，用-1表示自动计算，stmt是输出参数，编译后的语句的地址，最后一个不管了
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        fprintf(stderr, "准备SQL失败: %s\n", sqlite3_errmsg(db));//输出错误信息
        return -1;
    }

    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
    //将字符串 username 绑定到 SQL 语句的第 1 个占位符（? 的位置，SQLite 占位符索引从 1 开始）下面同理
    //stmt表示编译的sql语句对象
    sqlite3_bind_int(stmt, 2, score);
    sqlite3_bind_int(stmt, 3, time_used);

    int rc = sqlite3_step(stmt);//执行sql语句
    sqlite3_finalize(stmt);//释放内存
    //        SQLITE_DONE意思就是把事办了，加个！=就是没办成
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "保存分数失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    return 0;
}

// 游戏结束弹窗回调
static void on_game_over_dialog_response(GtkDialog *dialog, gint response_id, gpointer user_data) {
    // 保存分数（累计总分）和总用时
    if (is_recording) {
        time_t end_time = time(NULL);//time(NULL) 获取当前系统时间，存入 end_time 作为游戏结束时间。
        int time_used = (int)difftime(end_time, start_time); //计算时间差并转为int类型
        save_score(current_username, total_score, time_used);//自定义函数，就在上面，保存用户名分数及时间插入到数据库
        is_recording = FALSE; // 重置记录标志

        // 刷新排行榜
        if (global_rank_list != NULL) {
            update_rank_list(global_rank_list);//update_rank_list为创建排行榜界面函数，自定义的在上面
        }
    }

    gtk_widget_destroy(GTK_WIDGET(dialog));//关闭弹窗（对话框）
    gtk_widget_destroy(GTK_WIDGET(user_data)); // 关闭游戏窗口释放资源
}

// 过关弹窗回调
static void on_pass_dialog_response(GtkDialog *dialog, gint response_id, gpointer user_data) {
    GtkWidget *current_window = GTK_WIDGET(user_data);
    gtk_widget_destroy(GTK_WIDGET(dialog));//关闭窗口释放资源

    if (response_id == GTK_RESPONSE_OK) {//当用户点击下一关后进入下面的判断
        // 按难度进入下一关
        if (current_difficulty == EASY) {//判断用户刚刚游玩过的难度，如果是简单模式则继续进行
            int params[] = {20, 150}; // 一般难度参数
            GtkWidget *next_window = create_game_page(params[0], params[1]);//调用create_game_page函数以及难度参数建造一般难度
            g_signal_connect(next_window, "destroy", G_CALLBACK(on_game_window_destroy), NULL);//点×关闭界面的意思
            gtk_widget_show_all(next_window);//展示所有控件
        } else if (current_difficulty == MEDIUM) {//如果刚游玩过一般难度，那么久构建困难难度，逻辑同上
            int params[] = {30, 80}; // 困难难度参数
            GtkWidget *next_window = create_game_page(params[0], params[1]);
            g_signal_connect(next_window, "destroy", G_CALLBACK(on_game_window_destroy), NULL);
            gtk_widget_show_all(next_window);
        }
    }

    gtk_widget_destroy(current_window); // 关闭当前关卡窗口
}

// 检查是否过关
static void check_level_complete(GtkWidget *drawing_area) {
    int target = 0;
    const char *message = "";
    gboolean is_complete = FALSE;

    // 按难度设置目标分数
    switch (current_difficulty) {
        case EASY:
            target = 50;
            if (score >= target) {
                message = "恭喜过关";
                is_complete = TRUE;
            }
            break;
        case MEDIUM:
            target = 200;
            if (score >= target) {
                message = "恭喜过关";
                is_complete = TRUE;
            }
            break;
        case HARD:
            target = 500;
            if (score >= target) {
                message = "恭喜通关";
                is_complete = TRUE;
            }
            break;
    }

    if (is_complete) {
        // 停止当前定时器
        GtkWidget *game_window = gtk_widget_get_toplevel(drawing_area);    //获取游戏窗口
        //从game_window中获取计时器信息，GPOINTER_TO_UINT的作用是转换类型，把指针类型转换成定时器
        guint timer_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(game_window), "timer-id"));
        if (timer_id > 0) {
            g_source_remove(timer_id);//移除事件源，停止定时器
            //将游戏窗口中的"timer-id"数据设置为0（GUINT_TO_POINTER(0)），标记定时器已停止，避免重复操作。
            g_object_set_data(G_OBJECT(game_window), "timer-id", GUINT_TO_POINTER(0));
        }

        // 创建过关对话框
        GtkWidget *dialog = gtk_dialog_new_with_buttons(
                "关卡完成",
                GTK_WINDOW(game_window),//父界面为game_window,即产生在该界面之上
                GTK_DIALOG_MODAL,//将对话框设置为模态对话框，即用户必须先关闭这个对话框才能继续操作
                NULL
        );

        // 按难度添加按钮（困难难度无"下一关"）
        if (current_difficulty != HARD) {
            gtk_dialog_add_button(GTK_DIALOG(dialog), "下一关", GTK_RESPONSE_OK);
        } else {
            gtk_dialog_add_button(GTK_DIALOG(dialog), "确定", GTK_RESPONSE_OK);
        }

        // 设置弹窗内容
        //获取 GtkDialog 的内容区域容器（content_area），后续会向这个容器里添加自定义控件
        GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
        GtkWidget *label = gtk_label_new(message);//设置标签
        //   ↓  为 GtkLabel 设置富文本内容，支持用 Pango 标记语言（类似 HTML）定义文字样式
        gtk_label_set_markup(GTK_LABEL(label),//把标签类型转换为GTK_LABEL*型，作为参数接受内容
                             g_strdup_printf("<span size='xx-large'>%s</span>\n\n当前分数: %d", message, score));
        //g_strdup_printf用于拼接数据，上面的size='xx-large'意为设置字体为超大
        gtk_container_set_border_width(GTK_CONTAINER(content_area), 30);//设置内边距
        gtk_box_pack_start(GTK_BOX(content_area), label, TRUE, TRUE, 10);//把标签加入
        gtk_widget_show_all(dialog);//展示

        g_signal_connect(dialog, "response", G_CALLBACK(on_pass_dialog_response), game_window);//当点击确定时回调过关弹窗界面按钮
    }
}

// 释放障碍物内存
static void free_obstacles() {
    if (obstacles != NULL) {
        free(obstacles);
        obstacles = NULL;
        obstacle_count = 0;
    }
}

// 检查障碍物位置是否有效，下面那个函数要用，如果重叠了就不能用，返回FALSE
static gboolean is_position_valid(int x, int y, int snake_x, int snake_y) {
    //检查是否与蛇身重叠
    for(int i = 0; i < snake.length; i++){
        if(snake.body[i].x == x && snake.body[i].y == y){
            return FALSE;
        }
    }
    //检查是否与食物重叠
    if(food.x == x && food.y == y){
        return FALSE;
    }
    //检查是否与现有障碍物重叠
    for(int i = 0; i < obstacle_count; i++){
        if(obstacles[i].x == x && obstacles[i].y == y){
            return FALSE;
        }
    }
    return TRUE;
}

// 生成随机障碍物
static void generate_random_obstacles(int gridCount, int obstacle_num) {
    // 释放之前的障碍物
    free_obstacles();

    // 分配新内存
    obstacle_count = obstacle_num;
    obstacles = malloc(sizeof(Point) * obstacle_count);
    if (!obstacles) {
        g_error("内存分配失败");
        return;
    }

    int snake_x = gridCount / 2; // 蛇的初始位置x
    int snake_y = gridCount / 2; // 蛇的初始位置y

    // 生成障碍物
    for (int i = 0; i < obstacle_count; i++) {
        int attempts = 0;
        int max_attempts = 100; // 防止无限循环
        while (attempts < max_attempts) {
            int x = rand() % gridCount;//rand()为随机数，  %gridCount表示数据范围不超过游戏界面格数
            int y = rand() % gridCount;

            // 确保位置有效且不与蛇身、食物或其他障碍物重叠
            if (is_position_valid(x, y, snake_x, snake_y)) {//若不重叠就是TRUE，可以设置障碍物
                obstacles[i].x = x;
                obstacles[i].y = y;
                break;
            }
            attempts++;//进行下一次尝试
        }

        // 如果尝试100次仍找不到有效位置，则使用默认位置
        if (attempts >= max_attempts) {
            // 使用安全位置（左上角开始）
            obstacles[i].x = (i * 2) % gridCount;
            obstacles[i].y = (i * 3) % gridCount;

            // 确保位置有效     当有障碍物重叠无效时括号里的表达式为真
            if (!is_position_valid(obstacles[i].x, obstacles[i].y, snake_x, snake_y)) {
                // 如果还是无效，使用固定位置
                obstacles[i].x = (i + 1) * 2;
                obstacles[i].y = (i + 1) * 3;
                // 确保在网格范围内
                obstacles[i].x %= gridCount;
                obstacles[i].y %= gridCount;
            }
        }
    }
}

// 定时移动蛇
gboolean move_snake_timer(gpointer user_data) {
    GtkWidget *drawing_area = GTK_WIDGET(user_data);

    //如果游戏暂停，只刷新界面但不移动蛇
    if(is_paused){
        gtk_widget_queue_draw(drawing_area);//标记为进行重绘界面的状态
        return G_SOURCE_CONTINUE;      //保持状态，一直处于重绘状态
    }

    int grow = check_food_collision(&snake, &food); // 检测是否吃到食物，即是否发生碰撞

    if (grow) {
        score += 10; // 每吃一个食物加10分
        if (is_recording) {
            total_score += 10; // 累加到总分
        }

        // 重新生成食物（确保不在蛇身或障碍物上）
        gboolean valid_pos = FALSE;
        int max_attempts = 100; // 限制尝试次数，防止无限循环
        int attempts = 0;
        while (!valid_pos && attempts < max_attempts) {
            attempts++;
            food.x = rand() % game_grid_width;
            food.y = rand() % game_grid_height;

            // 检查是否与蛇身重叠
            valid_pos = TRUE;
            for (int i = 0; i < snake.length; i++) {
                if (snake.body[i].x == food.x && snake.body[i].y == food.y) {
                    valid_pos = FALSE;
                    break;
                }
            }

            // 检查是否与障碍物重叠
            if (valid_pos) {
                for (int i = 0; i < obstacle_count; i++) {
                    if (obstacles[i].x == food.x && obstacles[i].y == food.y) {
                        valid_pos = FALSE;
                        break;
                    }
                }
            }
        }

        // 检查是否过关
        check_level_complete(drawing_area);
    }

    move_snake(&snake, grow); // 调用函数移动蛇（grow=1时变长）

    // 碰撞检测（游戏结束）这里逻辑比较简单看会之前的检测碰撞函数就好了
    if (check_self_collision(&snake) ||
        check_wall_collision(&snake, game_grid_width, game_grid_height) ||
        check_obstacle_collision(&snake, obstacles, obstacle_count)) {

        // 停止定时器
        GtkWidget *game_window = gtk_widget_get_toplevel(drawing_area);//获取drawing_area所在的顶级容器
        guint timer_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(game_window), "timer-id"));
        if (timer_id > 0) {
            g_source_remove(timer_id);
            g_object_set_data(G_OBJECT(game_window), "timer-id", GUINT_TO_POINTER(0));
        }

        // 创建游戏结束弹窗
        GtkWidget *dialog = gtk_dialog_new_with_buttons(
                "游戏结束",
                GTK_WINDOW(game_window),
                GTK_DIALOG_MODAL,//设置为模态对话框
                "确定",
                GTK_RESPONSE_OK,
                NULL
        );
        //依旧是设置弹窗，逻辑不变
        GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
        GtkWidget *label = gtk_label_new("菜！");
        gtk_label_set_markup(GTK_LABEL(label),//依旧是设置为富文本框，字号为超大
                             g_strdup_printf("<span size='xx-large'>菜！</span>\n\n最终分数: %d", score));
        gtk_container_set_border_width(GTK_CONTAINER(content_area), 20);
        gtk_box_pack_start(GTK_BOX(content_area), label, TRUE, TRUE, 0);
        gtk_widget_show_all(dialog);

        g_signal_connect(dialog, "response", G_CALLBACK(on_game_over_dialog_response), game_window);//当用户做出回应后调用函数弹出游戏结束弹窗
        gtk_widget_queue_draw(drawing_area);//重绘，显示最终状态，比如蛇的最终位置
        return G_SOURCE_REMOVE; // 停止定时器
    }

    gtk_widget_queue_draw(drawing_area);//重绘界面当移动时更新蛇的位置
    return G_SOURCE_CONTINUE;//告诉GTK要continue，即要循环不断重绘不断更新蛇的位置
}

// 键盘控制(方向键改变方向，esc退出,p暂停)
static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
    //暂停和继续功能（按P）
    if(event->keyval == GDK_KEY_p || event->keyval == GDK_KEY_P){
        is_paused = !is_paused;//切换暂停状态
        gtk_widget_queue_draw(widget);//刷新界面显示暂停状态
        return TRUE;
    }
    //只有在游戏未暂停时才处理方向键
    if(is_paused)return FALSE;
    Direction new_dir = snake.dir;//把蛇的方向赋给new_dir
    switch (event->keyval) {
        case GDK_KEY_w:
        case GDK_KEY_W:
        case GDK_KEY_Up:
            new_dir = UP;
            break;
        case GDK_KEY_s:
        case GDK_KEY_S:
        case GDK_KEY_Down:
            new_dir = DOWN;
            break;
        case GDK_KEY_a:
        case GDK_KEY_A:
        case GDK_KEY_Left:
            new_dir = LEFT;
            break;
        case GDK_KEY_d:
        case GDK_KEY_D:
        case GDK_KEY_Right:
            new_dir = RIGHT;
            break;
        case GDK_KEY_Escape: // ESC键退出当前游戏
            gtk_widget_destroy(gtk_widget_get_toplevel(widget));
            return TRUE;
        default:
            return FALSE;
    }
    change_direction(&snake, new_dir);//调用函数改变方向
    return TRUE;
}

// 创建游戏界面
static GtkWidget* create_game_page(int gridCount, int speed_ms) {
    // 释放之前的障碍物
    free_obstacles();

    GtkWidget *game_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(game_window), "蛇，不弱！");

    // 窗口尺寸（固定大小）
    int windowWidth = GRID_WIDTH * gridCount;
    int windowHeight = GRID_HEIGHT * gridCount;
    gtk_window_set_default_size(GTK_WINDOW(game_window), windowWidth, windowHeight);//设置窗口大小
    gtk_window_set_resizable(GTK_WINDOW(game_window), FALSE);//把窗口设置为不可扩展

    // 设置当前难度（根据网格数判断）
    if (gridCount == 10) {
        current_difficulty = EASY;
        // 为菜鸟难度生成2个随机障碍点
        generate_random_obstacles(gridCount, 2);
    } else if (gridCount == 20) {
        current_difficulty = MEDIUM;
        // 为一般难度生成5个随机障碍点
        generate_random_obstacles(gridCount, 5);
    } else if (gridCount == 30) {
        current_difficulty = HARD;
        // 为困难难度生成10个随机障碍点
        generate_random_obstacles(gridCount, 10);
    }

    // 初始化游戏参数
    game_grid_width = gridCount;//游戏的地图大小
    game_grid_height = gridCount;
    init_snake(&snake, gridCount / 2, gridCount / 2); // 蛇初始位置居中
    score = 0; // 重置分数

    // 初始化食物位置（确保在网格内且有效）
    int max_attempts = 100;
    int attempts = 0;
    gboolean valid_pos = FALSE;
    while (!valid_pos && attempts < max_attempts) {//只有尝试次数小于最大尝试次数并且valid_pos为FALSE时才会再次初始化食物位置
        attempts++;
        food.x = rand() % game_grid_width;
        food.y = rand() % game_grid_height;

        // 检查是否在蛇身上
        valid_pos = TRUE;
        for (int i = 0; i < snake.length; i++) {
            if (snake.body[i].x == food.x && snake.body[i].y == food.y) {
                valid_pos = FALSE;
                break;
            }
        }

        // 检查是否在障碍物上
        if (valid_pos) {
            for (int i = 0; i < obstacle_count; i++) {
                if (obstacles[i].x == food.x && obstacles[i].y == food.y) {
                    valid_pos = FALSE;
                    break;
                }
            }
        }
        //只要初始化的第一个食物在蛇身上或者障碍物上就会把valid_pos重新设置为FALSE，并重新执行循环，直到找到正常的初始位置
    }

    // 如果尝试失败，使用备用位置（右上角）
    if (!valid_pos) {
        food.x = gridCount - 2;
        food.y = 2;
    }

    // 创建绘图区域
    GtkWidget *drawing_area = gtk_drawing_area_new();//创建绘画区域
    gtk_widget_set_size_request(drawing_area, windowWidth, windowHeight);//设定地图大小
    gtk_container_add(GTK_CONTAINER(game_window), drawing_area);//把绘画区域添加上去

    // 绑定信号
    g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(draw_game_callback), NULL);//调用画图的自定义函数画出网格等图案
    g_signal_connect(G_OBJECT(game_window), "key-press-event", G_CALLBACK(key_press_event), NULL);//为界面设置案件反馈，即按键盘后可以操纵蛇

    // 创建定时器并存储在窗口私有数据中
    guint timer_id = g_timeout_add(speed_ms, move_snake_timer, drawing_area);//创建定时器
    g_object_set_data(G_OBJECT(game_window), "timer-id", GUINT_TO_POINTER(timer_id));//把定时器的数据即时间储存在窗口中

    // 确保窗口显示在屏幕正中央
    gtk_window_set_position(GTK_WINDOW(game_window), GTK_WIN_POS_CENTER);
    return game_window;
}

// 窗口销毁时停止定时器
static void on_game_window_destroy(GtkWidget *widget, gpointer data) {
    // 获取窗口私有数据中的定时器ID
    guint timer_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "timer-id"));//从窗口对象中取出time_id
    if (timer_id > 0) {
        g_source_remove(timer_id);//停止定时器
    }
    // 不再调用 free_obstacles()，因为障碍物在创建新游戏时已经被重新分配
}

// 开始游戏回调
static void play_to_game(GtkWidget *button, gpointer data) {
    int *params = (int *)data;
    int gridCount = params[0];
    int speed_ms = params[1];

    // 设置记录标志
    is_recording = TRUE;
    total_score = 0; // 重置总分
    start_time = time(NULL); // 记录开始时间

    GtkWidget *game_window = create_game_page(gridCount, speed_ms);//创建游戏窗口并向其传入影响地图大小和蛇速度的参数
    g_signal_connect(game_window, "destroy", G_CALLBACK(on_game_window_destroy), NULL);

    // 确保窗口显示在屏幕正中央
    gtk_window_set_position(GTK_WINDOW(game_window), GTK_WIN_POS_CENTER);

    gtk_widget_show_all(game_window);
}

// 界面切换回调
static void switch_to_select2(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    gtk_stack_set_visible_child_name(stack, "select_diff");
}

static void switch_to_homepage(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    gtk_stack_set_visible_child_name(stack, "homepage");
}

static void switch_to_ranking(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    gtk_stack_set_visible_child_name(stack, "read_rank");

    // 每次切换到排行榜界面时刷新数据
    if (global_rank_list != NULL) {
        update_rank_list(global_rank_list);
    }
}

// 创建排行榜界面
static void update_rank_list(GtkWidget *rank_list) {
    const char *sql = "SELECT username, score, time_used FROM scores ORDER BY score DESC LIMIT 10;";//展示用户名，分数和用时，以分数排序，限制数量：10
    sqlite3_stmt *stmt;
    //如果sqlite语句编译成功就继续进行
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
        GString *rank_text = g_string_new("");
        int rank = 1;//表示成功收集到了一行数据 ↓
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            const char *username = (const char *)sqlite3_column_text(stmt, 0);//把提取到的数据赋给username,score,time_used
            int score = sqlite3_column_int(stmt, 1);
            int time_used = sqlite3_column_int(stmt, 2);

            // 格式化时间 (分:秒)
            int minutes = time_used / 60;
            int seconds = time_used % 60;

            g_string_append_printf(rank_text,
                                   "%d. %s - %d分 (%02d:%02d)\n\n",
                                   rank, username, score, minutes, seconds);//打印
            rank++;//从第一名往下顺
        }
        sqlite3_finalize(stmt);

        if (rank_text->len == 0) {
            g_string_append(rank_text, "暂无数据");
        }

        gtk_label_set_text(GTK_LABEL(rank_list), rank_text->str);//把排名信息放到排行榜当中
        g_string_free(rank_text, TRUE);//释放掉暂存数据的rank_text，方便再次循环时储存下一个排名的数据
    } else {
        gtk_label_set_text(GTK_LABEL(rank_list), "加载排行榜失败");
    }
}

// 登录回调
static void on_login_clicked(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);   //定义页面栈用来管理多个页面
    GtkWidget *login_page = gtk_stack_get_child_by_name(stack, "login_page");//获名为"login_page"的页面

    // 获取用户名和密码输入框
    GList *children = gtk_container_get_children(GTK_CONTAINER(login_page));//获取 login_page（容器）的所有子控件，返回 GList 链表
    GtkWidget *username_entry = g_list_nth_data(children, 0);//从链表中按索引取子控件：0是第一个子控件
    GtkWidget *password_entry = g_list_nth_data(children, 1);//同理

    const char *username = gtk_entry_get_text(GTK_ENTRY(username_entry));//存入输入的内容
    const char *password = gtk_entry_get_text(GTK_ENTRY(password_entry));

    if (login_user(username, password) == 0) {
        // 保存当前用户名
        strncpy(current_username, username, sizeof(current_username) - 1);
        gtk_stack_set_visible_child_name(stack, "homepage");//把主页变为可见，其他界面变为不可见，相当于界面跳转
    } else {
        GtkWidget *dialog = gtk_message_dialog_new(NULL,
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,//父对话框销毁后也跟着销毁，但它的销毁不影响父对话框
                                                   GTK_MESSAGE_ERROR,//显示错误提示信息
                                                   GTK_BUTTONS_CLOSE,
                                                   "用户名或密码错误");
        gtk_dialog_run(GTK_DIALOG(dialog));//阻塞当前线程，显示对话框并等待用户响应（如点击 "确定""取消" 按钮）。
        gtk_widget_destroy(dialog);//关闭销毁界面
    }
}

// 注册回调
static void on_register_clicked(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    gtk_stack_set_visible_child_name(stack, "register_page");
}

// 注册提交回调
static void on_register_submit_clicked(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    GtkWidget *register_page = gtk_stack_get_child_by_name(stack, "register_page");

    // 获取输入框内容
    GList *children = gtk_container_get_children(GTK_CONTAINER(register_page));
    GtkWidget *username_entry = g_list_nth_data(children, 0);
    GtkWidget *password_entry = g_list_nth_data(children, 1);
    GtkWidget *confirm_password_entry = g_list_nth_data(children, 2);//这里上面也说过了就不再写了我写不下去了要

    const char *username = gtk_entry_get_text(GTK_ENTRY(username_entry));
    const char *password = gtk_entry_get_text(GTK_ENTRY(password_entry));
    const char *confirm_password = gtk_entry_get_text(GTK_ENTRY(confirm_password_entry));
    // 验证密码一致性
    if (strcmp(password, confirm_password) != 0) {
        GtkWidget *dialog = gtk_message_dialog_new(NULL,
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_MESSAGE_ERROR,
                                                   GTK_BUTTONS_CLOSE,
                                                   "两次输入的密码不一致");
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);
        return;
    }
    if (register_user(username, password) == 0) {
        gtk_stack_set_visible_child_name(stack, "login_page");//这一块基本没啥难度大家自己看看吧就
    } else {
        GtkWidget *dialog = gtk_message_dialog_new(NULL,
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_MESSAGE_ERROR,
                                                   GTK_BUTTONS_CLOSE,
                                                   "注册失败，用户名可能已存在");
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);
    }
}

// 返回登录界面
static void on_back_to_login_clicked(GtkWidget *button, gpointer data) {
    GtkStack *stack = GTK_STACK(data);
    gtk_stack_set_visible_child_name(stack, "login_page");
}

// 初始化数据库
static int init_database() {
    int rc = sqlite3_open("snake_game.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 创建用户表
    const char *user_sql = "CREATE TABLE IF NOT EXISTS users ("
                           "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                           "username TEXT UNIQUE NOT NULL,"
                           "password TEXT NOT NULL);";

    // 创建分数表（新增）
    const char *score_sql = "CREATE TABLE IF NOT EXISTS scores ("
                            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                            "username TEXT NOT NULL,"
                            "score INTEGER NOT NULL,"
                            "time_used INTEGER NOT NULL);"; // 游戏耗时（秒）

    char *err_msg = NULL;

    // 执行用户表创建
    rc = sqlite3_exec(db, user_sql, 0, 0, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "创建用户表失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return -1;
    }

    // 执行分数表创建
    rc = sqlite3_exec(db, score_sql, 0, 0, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "创建分数表失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return -1;
    }

    return 0;
}

// 注册用户（使用参数化查询放置SQL注入）
static int register_user(const char *username, const char *password) {
    const char *sql = "INSERT INTO users (username, password) VALUES (?, ?);";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        fprintf(stderr, "准备SQL失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, password, -1, SQLITE_STATIC);
    int rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "注册失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    return 0;
}

// 登录用户
static int login_user(const char *username, const char *password) {
    const char *sql = "SELECT password FROM users WHERE username = ?;";
    sqlite3_stmt *stmt;

    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        fprintf(stderr, "准备SQL失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);

    int rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        const unsigned char *stored_password = sqlite3_column_text(stmt, 0);
        if (stored_password && strcmp(password, (const char*)stored_password) == 0) {
            sqlite3_finalize(stmt);
            return 0;
        }
    }
    sqlite3_finalize(stmt);
    return -1;
}

// 创建登录界面
static GtkWidget* create_login_page(GtkStack *stack) {
    GtkWidget *login_page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_container_set_border_width(GTK_CONTAINER(login_page), 20);

    // 用户名输入框
    GtkWidget *username_entry = gtk_entry_new();
    gtk_entry_set_placeholder_text(GTK_ENTRY(username_entry), "用户名");
    gtk_box_pack_start(GTK_BOX(login_page), username_entry, FALSE, FALSE, 10);

    // 密码输入框
    GtkWidget *password_entry = gtk_entry_new();
    gtk_entry_set_placeholder_text(GTK_ENTRY(password_entry), "密码");
    gtk_entry_set_visibility(GTK_ENTRY(password_entry), FALSE);
    gtk_box_pack_start(GTK_BOX(login_page), password_entry, FALSE, FALSE, 10);

    // 登录按钮
    GtkWidget *login_button = gtk_button_new_with_label("登录");
    gtk_box_pack_start(GTK_BOX(login_page), login_button, FALSE, FALSE, 10);

    // 注册按钮
    GtkWidget *register_button = gtk_button_new_with_label("注册");
    gtk_box_pack_start(GTK_BOX(login_page), register_button, FALSE, FALSE, 10);

    // 连接信号
    g_signal_connect(login_button, "clicked", G_CALLBACK(on_login_clicked), stack);
    g_signal_connect(register_button, "clicked", G_CALLBACK(on_register_clicked), stack);
    return login_page;
}


// 创建注册界面
static GtkWidget* create_register_page(GtkStack *stack) {
    GtkWidget *register_page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_container_set_border_width(GTK_CONTAINER(register_page), 20);

    // 用户名输入框
    GtkWidget *username_entry = gtk_entry_new();
    gtk_entry_set_placeholder_text(GTK_ENTRY(username_entry), "用户名");
    gtk_box_pack_start(GTK_BOX(register_page), username_entry, FALSE, FALSE, 10);

    // 密码输入框
    GtkWidget *password_entry = gtk_entry_new();
    gtk_entry_set_placeholder_text(GTK_ENTRY(password_entry), "密码");
    gtk_entry_set_visibility(GTK_ENTRY(password_entry), FALSE);
    gtk_box_pack_start(GTK_BOX(register_page), password_entry, FALSE, FALSE, 10);

    // 确认密码输入框
    GtkWidget *confirm_password_entry = gtk_entry_new();
    gtk_entry_set_placeholder_text(GTK_ENTRY(confirm_password_entry), "确认密码");
    gtk_entry_set_visibility(GTK_ENTRY(confirm_password_entry), FALSE);
    gtk_box_pack_start(GTK_BOX(register_page), confirm_password_entry, FALSE, FALSE, 10);

    // 注册按钮
    GtkWidget *register_button = gtk_button_new_with_label("注册");
    gtk_box_pack_start(GTK_BOX(register_page), register_button, FALSE, FALSE, 10);

    // 返回按钮
    GtkWidget *back_button = gtk_button_new_with_label("返回");
    gtk_box_pack_start(GTK_BOX(register_page), back_button, FALSE, FALSE, 10);

    // 连接信号
    g_signal_connect(register_button, "clicked", G_CALLBACK(on_register_submit_clicked), stack);
    g_signal_connect(back_button, "clicked", G_CALLBACK(on_back_to_login_clicked), stack);
    return register_page;
}

int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);
    srand(time(NULL));

    // 初始化数据库
    if (init_database() != 0) {
        return -1;
    }

    // 主窗口
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "蛇，不弱！ - 登录");
    gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    // 主布局
    GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    GtkStack *stack = gtk_stack_new();
    gtk_box_pack_start(GTK_BOX(vbox), stack, TRUE, TRUE, 0);
    gtk_stack_set_transition_type(stack, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);//设置界面切换动画为左右滑动
    gtk_stack_set_transition_duration(stack, 300);//左右滑动时间300ms

    // 添加登录界面
    GtkWidget *login_page = create_login_page(stack);
    gtk_stack_add_titled(stack, login_page, "login_page", "登录");

    // 添加注册界面
    GtkWidget *register_page = create_register_page(stack);
    gtk_stack_add_titled(stack, register_page, "register_page", "注册");

    // 添加主页界面
    GtkWidget *homepage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 25);
    gtk_container_set_border_width(GTK_CONTAINER(homepage), 20);
    gtk_stack_add_titled(stack, homepage, "homepage", "主页");

    const int BUTTON_WIDTH = 200;
    const int BUTTON_HEIGHT = 50;

    // 开始游戏按钮（默认菜鸟难度）
    GtkWidget *button_start = gtk_button_new_with_label("开始游戏");
    gtk_widget_set_margin_top(button_start, 90);
    gtk_widget_set_size_request(button_start, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_box_pack_start(GTK_BOX(homepage), button_start, FALSE, FALSE, 0);
    gtk_widget_set_halign(button_start, GTK_ALIGN_CENTER);

    int params1[2] = {10, 250}; // 菜鸟：10x10网格，250ms/步
    g_signal_connect(button_start, "clicked", G_CALLBACK(play_to_game), params1);

    // 选择关卡按钮
    GtkWidget *button_select = gtk_button_new_with_label("选择关卡");
    gtk_widget_set_size_request(button_select, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_box_pack_start(GTK_BOX(homepage), button_select, FALSE, FALSE, 0);
    gtk_widget_set_halign(button_select, GTK_ALIGN_CENTER);
    g_signal_connect(button_select, "clicked", G_CALLBACK(switch_to_select2), stack);

    // 排行榜按钮
    GtkWidget *button_rank = gtk_button_new_with_label("排行榜");
    gtk_widget_set_size_request(button_rank, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_box_pack_start(GTK_BOX(homepage), button_rank, FALSE, FALSE, 0);
    gtk_widget_set_halign(button_rank, GTK_ALIGN_CENTER);
    g_signal_connect(button_rank, "clicked", G_CALLBACK(switch_to_ranking), stack);

    // 2. 选关界面
    GtkWidget *select_diff = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_stack_add_titled(stack, select_diff, "select_diff", "选关");

    // 返回主页按钮
    GtkWidget *button_back_homepage = gtk_button_new_with_label("返回主页");
    gtk_widget_set_margin_top(button_back_homepage,20);
    gtk_widget_set_size_request(button_back_homepage, 90, 40);
    gtk_box_pack_start(GTK_BOX(select_diff), button_back_homepage, FALSE, FALSE, 0);
    gtk_widget_set_halign(button_back_homepage, GTK_ALIGN_CENTER);
    g_signal_connect(button_back_homepage, "clicked", G_CALLBACK(switch_to_homepage), stack);

    // 难度选择按钮
    GtkWidget *button_simple = gtk_button_new_with_label("菜鸟");
    GtkWidget *button_commen = gtk_button_new_with_label("一般");
    GtkWidget *button_difficult = gtk_button_new_with_label("困难");
    gtk_widget_set_size_request(button_simple, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_widget_set_size_request(button_commen, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_widget_set_size_request(button_difficult, BUTTON_WIDTH, BUTTON_HEIGHT);
    gtk_box_pack_start(GTK_BOX(select_diff), button_simple, FALSE, FALSE, 5);
    gtk_widget_set_margin_top(button_simple, 30);
    gtk_box_pack_start(GTK_BOX(select_diff), button_commen, FALSE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(select_diff), button_difficult, FALSE, FALSE, 5);
    gtk_widget_set_halign(button_simple, GTK_ALIGN_CENTER);
    gtk_widget_set_halign(button_commen, GTK_ALIGN_CENTER);
    gtk_widget_set_halign(button_difficult, GTK_ALIGN_CENTER);

    // 难度参数（网格数，移动间隔ms）
    int params_simple[2] = {10, 250}; // 菜鸟：10x10，250ms
    int params_commen[2] = {20, 150}; // 一般：20x20，150ms
    int params_difficult[2] = {30, 80}; // 困难：30x30，80ms

    g_signal_connect(button_simple, "clicked", G_CALLBACK(play_to_game), params_simple);
    g_signal_connect(button_commen, "clicked", G_CALLBACK(play_to_game), params_commen);
    g_signal_connect(button_difficult, "clicked", G_CALLBACK(play_to_game), params_difficult);

    // 3. 排行榜界面
    GtkWidget *read_rank = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_stack_add_titled(stack, read_rank, "read_rank", "排行榜");

    // 返回主页按钮
    GtkWidget *button_back_homepage1 = gtk_button_new_with_label("返回主页");
    gtk_widget_set_margin_top(button_back_homepage1,20);
    gtk_widget_set_size_request(button_back_homepage1, 90, 40);
    gtk_box_pack_start(GTK_BOX(read_rank), button_back_homepage1, FALSE, FALSE, 0);
    gtk_widget_set_halign(button_back_homepage1, GTK_ALIGN_CENTER);
    g_signal_connect(button_back_homepage1, "clicked", G_CALLBACK(switch_to_homepage), stack);

    // 排行榜内容
    GtkWidget *rank_label = gtk_label_new("排行榜");
    gtk_label_set_markup(GTK_LABEL(rank_label), "<span size='xx-large'>排行榜</span>");
    gtk_box_pack_start(GTK_BOX(read_rank), rank_label, FALSE, FALSE, 20);
    gtk_widget_set_halign(rank_label, GTK_ALIGN_CENTER);
    // ======== 添加滚动窗口 ========
    // 创建滚动窗口
    GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
                                   GTK_POLICY_AUTOMATIC,   // 水平滚动条策略
                                   GTK_POLICY_ALWAYS);     // 垂直滚动条策略（始终显示）
    gtk_box_pack_start(GTK_BOX(read_rank), scrolled_window, TRUE, TRUE, 10);
    gtk_widget_set_size_request(scrolled_window, 350, 300); // 设置滚动窗口大小

    // 创建视口容器
    GtkWidget *viewport = gtk_viewport_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scrolled_window), viewport);


    GtkWidget *rank_list = gtk_label_new("");
    gtk_label_set_justify(GTK_LABEL(rank_list), GTK_JUSTIFY_CENTER);
    gtk_label_set_line_wrap(GTK_LABEL(rank_list), TRUE); // 允许文本换行
    gtk_label_set_line_wrap_mode(GTK_LABEL(rank_list), PANGO_WRAP_WORD); // 按单词换行
    gtk_container_add(GTK_CONTAINER(viewport), rank_list);
    gtk_widget_set_halign(rank_list, GTK_ALIGN_CENTER);
    // ======== 滚动窗口结束 ========

    // 设置全局排行榜标签
    global_rank_list = rank_list;

    // 初始化排行榜数据
    update_rank_list(rank_list);

    // 默认显示登录界面
    gtk_stack_set_visible_child_name(stack, "login_page");
    gtk_widget_show_all(window);
    gtk_main();

    // 清理
    free_obstacles();
    sqlite3_close(db);

    return 0;
}